﻿#include "db_api_.h"

static int add_record(int id, IMAGERECORD* rec)
{
	int res = 0;
	unsigned int br;
	res += f_lseek(&hDB->fdb, sizeof(IMAGERECORD)*(long long)id);
	res += f_write(&hDB->fdb, rec, sizeof(IMAGERECORD), &br);
	return res;
}

static int parse(const char* path, const char* fname)
{
	IMAGERECORD rec = { 0 };
	if ((file_type(path) & MEDIA_HI_IMAGE) == 0)return 0;

	strcpy(rec.path, path);

	name_to_utf8((const unsigned char*)fname, (unsigned char*)rec.fname, MAXUTF8NAME);
	
	return  add_record(hDB->image_count++, &rec);
}

static int scan_file(char* root)
{
	int res = 0;
	DIR dj;         /* Directory object */
	FILINFO fno;    /* File information */

	res += f_findfirst(&dj, &fno, root, "*.*");	if (res)return res;

	while (res == FR_OK && fno.fname[0])
	{
		if ((fno.fattrib & (AM_ARC | AM_DIR | AM_HID | AM_SYS)) == AM_ARC)
		{
			char path[MAXPATH];
			int tmp_len = strlen(root) + strlen("\\") + strlen(fno.fname);
   			if (tmp_len < MAXPATH)
			{
				strcpy(path, root);
				strcat(path, "\\");
				strcat(path, fno.fname);

				res += parse(path, fno.fname);			if (res)break;
				if (hDB->image_count >= MAXRECORD) break;
			}
		}
		hDB->cb(-555, (hDB->percent++/50)%100);
		res += f_findnext(&dj, &fno);				if (res)break;
		DB_SLP
	}

	res += f_closedir(&dj);
	return res;
}

static int scanfile(char* root, int* nest, const char * ignore_dir[])
{
	int res = 0;
	DIR dj;         /* Directory object */
	FILINFO fno;    /* File information */

	if ((*nest) > NEST)return res;
	if (hDB->image_count >= MAXRECORD)return res;

	res += scan_file(root);

	res += f_findfirst(&dj, &fno, root, "*");	if (res)return 0;

	while (res == FR_OK && fno.fname[0])
	{
		if ((fno.fattrib & AM_DIR)
			&& (0 != strcmp(fno.fname, "."))
			&& (0 != strcmp(fno.fname, "..")))
		{
			char path[MAXPATH];
			int tmp_len = strlen(root) + strlen("\\") + strlen(fno.fname);
   			if (tmp_len < MAXPATH)
			{
				strcpy(path, root);
				strcat(path, "\\");
				strcat(path, fno.fname);
	
				if (0 == is_ignore_dir(path) && 0 == is_ignore_dirA(path, ignore_dir))
				{
					(*nest)++;
					res += scanfile(path, nest, ignore_dir);	if (res)break;
					(*nest)--;
					if (hDB->image_count >= MAXRECORD)	break;
				}
			}

		}
		res += f_findnext(&dj, &fno);			if (res)break;
		DB_SLP
	}

	res += f_closedir(&dj);

	return res;
}

#if SORT == 1
static void get_sortid(char* path, unsigned long long id[2])
{
	int i;
	int len;
	char name[MAXPATH] = {0};
	split_path(path, NULL, NULL, name, NULL);
	len = strlen(name);
	id[0] = id[1] = 0;

	for(i=0; i<8 && i<len; i++)
	{
		unsigned long long c = (unsigned long long)(unsigned char)(name[i]);
		id[0] |= c<<((7-i)*8);
	}
	for(i=8; i<16 && i<len; i++)
	{
		unsigned long long c = (unsigned long long)(unsigned char)(name[i]);
		id[1] |= c<<((15-i)*8);
	}
}

static int load_sort(SORTNODE *tmp)
{
	unsigned int i;
	FIL f;
	int res = 0;
	unsigned int br;
	IMAGERECORD rec;

	res += f_open(&f, (const char*)(F_DBIMAGE), (unsigned char)(FA_READ));
	if(res) return -1;

	for (i = 0; i < hDB->image_count; i++)
	{
		tmp[i].offset = (int)f_tell(&f);
		res += f_read(&f, &rec, sizeof(IMAGERECORD), &br);
		if (FR_OK == res && sizeof(IMAGERECORD) == br)
		{
			get_sortid(rec.path, tmp[i].id);
		}
	}

	res += f_close(&f);
	return res;
}

static int save_sort(SORTNODE *tmp)
{
	unsigned int i;
	int res = 0;
	unsigned int br;
	IMAGERECORD rec;
	FIL f_src, f_des;

	res += f_open(&f_src, (const char*)(F_DBIMAGE), (unsigned char)(FA_READ));
	if(res) return -1;
	res += f_open(&f_des, (const char*)(F_SORT), (unsigned char)(FA_READ | FA_WRITE | FA_CREATE_ALWAYS));
	if(res) return -1;

	for(i=0; i<hDB->image_count; i++)
	{
		res += f_lseek(&f_src, tmp[i].offset);
		res += f_read(&f_src, &rec, sizeof(IMAGERECORD), &br);
		res += f_write(&f_des, &rec, sizeof(IMAGERECORD), &br);
	}

	res += f_close(&f_src);
	res += f_close(&f_des);

	res += f_unlink((const char*)(F_DBIMAGE));
	res += f_rename((const char*)(F_SORT), (const char*)(F_DBIMAGE));

	return res;
}

static int sort(void)
{
	int res = 0;
	SORTNODE *tmp = 0;

	assert(MAXRECORD >= hDB->image_count);
	if(hDB->image_count < 2) return 0;

	tmp = (SORTNODE*)OAL_malloc(sizeof(SORTNODE) * hDB->image_count);
	if (tmp == 0)
	{
		hDB->cb(-888, 0);
		return -1;
	}

	res += load_sort(tmp);
	if (res == FR_OK)
	{
		_db_sort(tmp, hDB->image_count);
		res += save_sort(tmp);
	}

	OAL_free(tmp);
	return res;
}
#endif

int image_build(const char * ignore_dir[])
{
	int res = 0;
	int nest = 0;

	assert(hDB->mount == 1);

	hDB->image_count = 0;
	hDB->percent = 0;

	res += f_open(&hDB->fdb, (const char*)(F_DBIMAGE), (unsigned char)(FA_READ | FA_WRITE));
	res += scanfile(SDROOT, &nest, ignore_dir);
	hDB->dirty &= ~MODULE_IMAGE;
	res += f_close(&hDB->fdb);
#if SORT == 1
	res += sort();
#endif
	hDB->cb(-666, 100);
	return 0;
}

int get_image_records(unsigned int offset, IMAGERECORD* records, unsigned int cnt)
{
	unsigned int i = 0;
	int res = 0;
	unsigned int br;
	res += f_open(&hDB->fdb, (const char*)(F_DBIMAGE), (unsigned char)(FA_READ | FA_WRITE));
	res += f_lseek(&hDB->fdb, sizeof(IMAGERECORD) * (long long)offset);
	for (i = 0; i < cnt && i + offset < hDB->image_count; i++)
	{
		res += f_read(&hDB->fdb, &records[i], sizeof(IMAGERECORD), &br);
	}
	res += f_close(&hDB->fdb);
	return res ? -1 : i;
}

int get_image_name(unsigned int offset, RECUTF8NAME* fname, unsigned int cnt)
{
	unsigned int i = 0;
	int res = 0;
	unsigned int br;
	res += f_open(&hDB->fdb, (const char*)(F_DBIMAGE), (unsigned char)(FA_READ | FA_WRITE));
	res += f_lseek(&hDB->fdb, sizeof(IMAGERECORD) * (long long)offset);
	for (i = 0; i < cnt && i + offset < hDB->image_count; i++)
	{
		IMAGERECORD rec;
		res += f_read(&hDB->fdb, &rec, sizeof(IMAGERECORD), &br);
		memcpy(fname[i], rec.fname, MAXUTF8NAME);
	}
	res += f_close(&hDB->fdb);
	return res ? -1 : i;
}

#if SORT == 1

int delete_image(char* path)
{
	unsigned int i = 0;
	int res = 0;
	unsigned int br;
	IMAGERECORD rec;
	FIL f;

	res += f_open(&hDB->fdb, (const char*)(F_DBIMAGE), (unsigned char)(FA_READ));
	res += f_open(&f, (const char*)(F_SORT), (unsigned char)(FA_READ | FA_WRITE | FA_CREATE_ALWAYS));

	for (i = 0; i < hDB->image_count; i++)
	{
		res += f_read(&hDB->fdb, &rec, sizeof(IMAGERECORD), &br);
		if (dircmp(path, rec.path))
		{
			res += f_write(&f, &rec, sizeof(IMAGERECORD), &br);
		}
		else
		{
			for (++i; i < hDB->image_count; i++)
			{
				res += f_read(&hDB->fdb, &rec, sizeof(IMAGERECORD), &br);
				res += f_write(&f, &rec, sizeof(IMAGERECORD), &br);
			}
			hDB->image_count--;
			break;
		}
	}

	res += f_close(&hDB->fdb);
	res += f_close(&f);

	res += f_unlink((const char*)(F_DBIMAGE));
	res += f_rename((const char*)(F_SORT), (const char*)(F_DBIMAGE));

	return res;
}

#else

int delete_image(char* path)
{
	unsigned int i = 0;
	int res = 0;
	unsigned int br;
	IMAGERECORD rec;

	res += f_open(&hDB->fdb, (const char*)(F_DBIMAGE), (unsigned char)(FA_READ | FA_WRITE));

	for (i = 0; i < hDB->image_count; i++)
	{
		res += f_read(&hDB->fdb, &rec, sizeof(IMAGERECORD), &br);
		if (dircmp(path, rec.path) == 0)
		{
			long long ofs = f_tell(&hDB->fdb) - sizeof(IMAGERECORD);
			hDB->image_count--;
			res += f_lseek(&hDB->fdb, sizeof(IMAGERECORD) * (hDB->image_count));
			res += f_read(&hDB->fdb, &rec, sizeof(IMAGERECORD), &br);
			res += f_lseek(&hDB->fdb, ofs);
			res += f_write(&hDB->fdb, &rec, sizeof(IMAGERECORD), &br);
			break;
		}
	}

	res += f_close(&hDB->fdb);
	return res;
}

#endif
